/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#include "DrivePath.hpp"
#include "owndebug.h"
#include "Machine.hpp"
#include "Devices.hpp"

using namespace MuRo;

CDrivePath::CDrivePoint::CDrivePoint(CDrivePath *path)
  :x(0),y(0),path(path),selected(false)
{
  SetCallback(this);
}

void CDrivePath::CDrivePoint::Draw(const TViewParams &view)
{
  float pointSize=5.0;
  
  this->view=view;
  
  if (!path->device->machine->IsSelected() || !path->editable || 
       path->device->machine->GetOperationMode()!=KOperModeCoordDrive ||
       !(path->device->machine->GetCoordinateDriveDevice()==path->device))
    pointSize=2.0;
  
  if ((selected || path->selected) && path->device->machine->IsSelected())
  {
    glColor3f(1,1,1);
  } else {
    glColor3f(0.8,0.6,0);
  }
  glBegin(GL_QUADS);
  glVertex3f(x-pointSize/view.Scale,y+pointSize/view.Scale,10);
  glVertex3f(x+pointSize/view.Scale,y+pointSize/view.Scale,10);
  glVertex3f(x+pointSize/view.Scale,y-pointSize/view.Scale,10);
  glVertex3f(x-pointSize/view.Scale,y-pointSize/view.Scale,10);
  glEnd();
      
}

void CDrivePath::CDrivePoint::DrawPickable()
{
  if (path->device->machine->IsSelected() &&
      path->device->machine->GetCoordinateDriveDevice()==path->device &&
      path->device->machine->GetOperationMode()==KOperModeCoordDrive)
    Draw(view);
}

void CDrivePath::CDrivePoint::OnPick(TGLPickEvent event)
{
//   if (path->device->machine->GetCoordinateDriveDevice()==path->device &&
//       path->device->machine->GetOperationMode()==KOperModeCoordDrive)
//   {
    //dPrint(1,"point picked");
    selected=!selected;
    path->selected=false;
    if (path->selectedPoint && path->selectedPoint!=this)
      path->selectedPoint->selected=false;
    path->selectedPoint=this;
//   }
}

void CDrivePath::CDrivePoint::OnDrag(TGLPickEvent event)
{
//   if (path->device->machine->GetCoordinateDriveDevice()==path->device &&
//       path->machine->GetOperationMode()==KOperModeCoordDrive)
//   {
    x=event.GlX;
    y=event.GlY;
//   }
}

/******************************************************************************/

CDrivePath::CDrivePath(CCoordinateDriveDevice *device)
  :selected(false),editable(true),selectedPoint(NULL),pickingContext(NULL),device(device)//machine(machine)
{
  SetCallback(this);
}

CDrivePath::~CDrivePath()
{
  Clear();
  if (pickingContext)
    pickingContext->RemovePickable(this);
}

void CDrivePath::SetPickingContext(CGLPickingContext *context)
{
  if (pickingContext)
    pickingContext->RemovePickable(this);
  pickingContext=context;
  pickingContext->AddPickable(this);
}

void CDrivePath::Draw(const TViewParams &view)
{
  Lock();
  if (points.size())
  {
    std::list<CDrivePoint*>::iterator i,ii;
    for (i=points.begin(); i!=points.end(); i++)
    {
      (*i)->Draw(view);
    }
    if (selected)
    {
      glColor3f(1,1,1);
    } else {
      glColor3f(0.6,0.4,0);
    }
    ii=points.begin();
    i=ii;
    i++;
    glBegin(GL_LINES);
    for (; i!=points.end(); i++)
    {
      glVertex2f((*ii)->x, (*ii)->y);
      glVertex2f((*i)->x, (*i)->y);
      ii++;
    }
    glEnd();
  }
  Unlock();
}

void CDrivePath::AddPoint(float x, float y)
{
  Lock();
  //dPrint(1,"Added point");
  CDrivePoint *p=new CDrivePoint(this);
  p->x=x;
  p->y=y;
  points.push_back(p);
  if (editable)
    pickingContext->AddPickable(p);
  Unlock();
}

void CDrivePath::RemoveSelectedPoints()
{
  Lock();
  std::list<CDrivePoint*>::iterator i,ii;
  for (i=points.begin(); i!=points.end(); )
  {
    ii=i;
    ii++;
    if (selected || (*i)->selected==true)
    {
      if (editable)
        pickingContext->RemovePickable(*i);
      delete *i;
      points.erase(i);
    }
    i=ii;
  }
  if (selected)
    selected=false;
  selectedPoint=NULL;
  Unlock();
}

void CDrivePath::Clear()
{
  
  std::list<CDrivePoint*>::iterator i;
  for (i=points.begin(); i!=points.end(); i++)
  {
    (*i)->selected=true;
    //delete *i;
  }
  RemoveSelectedPoints();
  Lock();
  points.clear();
  Unlock();
}

void CDrivePath::DrawPickable()
{
  Lock();
  if (device->machine->IsSelected() &&
      device->machine->GetCoordinateDriveDevice()==device &&
      device->machine->GetOperationMode()==KOperModeCoordDrive)
  {
//   if (device->machine->IsSelected())
//   {
    if (points.size())
    {
      std::list<CDrivePoint*>::iterator i,ii;
      ii=points.begin();
      i=ii;
      i++;
      glBegin(GL_LINES);
      for (; i!=points.end(); i++)
      {
        glVertex2f((*ii)->x, (*ii)->y);
        glVertex2f((*i)->x, (*i)->y);
        
        ii++;
      }
      glEnd();
    }
  }
  Unlock();
}

void CDrivePath::OnPick(TGLPickEvent event)
{
  if (selectedPoint)
    selectedPoint->selected=false;
  selected=!selected;
  px=event.GlX;
  py=event.GlY;
}

void CDrivePath::OnDrag(TGLPickEvent event)
{
  std::list<CDrivePoint*>::iterator i;
  for (i=points.begin(); i!=points.end(); i++)
  {
    (*i)->x+=event.GlX-px;
    (*i)->y+=event.GlY-py;
  }
  px=event.GlX;
  py=event.GlY;
}

void CDrivePath::SendPoints(
           MaCI::CoordinateDrive::CCoordinateDriveClient *client)
{
  Lock();
  std::list<CDrivePoint*>::iterator i;
  for (i=points.begin(); i!=points.end(); i++)
  {
    client->SetCoordinate((*i)->x,(*i)->y);
  }
  Unlock();
}

